package modelo;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

import modelo.listener.GameListener;

import constants.Constants;
import constants.Constants.Colors;
import controller.ClientHandler;



public class Player implements Comparable<Player>{
	
	private static int playerNum=0; //variable estatica para ir asignando numeros unicos a cada jugador
	private int playerNumber;             //numero del jugador
	private Colors color;
	private String playerName;
	private Square ubication=null;
	private boolean hasMoved=false;
	private boolean votoSilencio=false;
	private boolean libraryVisited=false;
	private Set<Monje> monkCards=null;
	private Set<Suspect> hojaSospechosos=null;
	private List<CryptaCard> criptaCardList;
	private ClientHandler connection;
	private List<GameListener> listeners;
	private int maxMoves = Constants.MAX_MOVES;
	private int score = 0;
	
	
	/**
	 * Constructor for player object.
	 * <p> 
	 * @param  name the player's name
	 * @param  color a color for the player, it's an enum type
	 * @
	 */
	public Player(String name,Colors color,ClientHandler connection,List<GameListener> listeners){
		playerName=name;
		this.listeners = listeners;
		this.color=color;
		this.connection=connection;
		playerNumber=++playerNum;
		ubication= new Square(0,"no ubicado");
		criptaCardList = new ArrayList<CryptaCard>();
	}
	
	
	//GETTERS
	public ClientHandler getClientHandler(){
		return connection;
	}
	
	public Square getUbication() {
		return ubication;
	}
	
	public Set<Monje> getMonkCards(){
		return monkCards;
	}

	public Set<Suspect> getHojaSospechosos(){
		return hojaSospechosos;
	}
	
	public int getPlayerNumber() {
		return playerNumber;
	}

	public Colors getColor() {
		return color;
	}

	public String getPlayerName() {
		return playerName;
	}
	
	public int getScore(){
		return score;
	}
	
	public int getMaxMoves() {
		return maxMoves;
	}

	public List<CryptaCard> getCriptaCardList() {
		return criptaCardList;
	}


	public boolean isLibraryVisited() {
		return libraryVisited;
	}
	//GETTERS
	

	//SETTERS
	public void setHojaDeSospechosos(Set<Suspect> set){
		if(hojaSospechosos==null) {
			hojaSospechosos = set;
			System.out.println(hojaSospechosos);
		}
		//AGREGO METODO PARA EL CASO QUE TENGA UNA LISTA ME ACTUALICE SUS SUSPECTS
	}
	
	
	public void setMaxMoves(int maxMoves) {
		this.maxMoves = maxMoves;
	}

	public void setUbication(Square ubication) {
		if (this.ubication!=null) this.ubication.removePlayer(this);
		this.ubication = ubication;
		ubication.addPlayer(this);
		hasMoved = true;
		for (GameListener listener : listeners) {
			listener.playerHasMoved(ubication.getSquareNum(), playerNumber); 
		}
	}

	public void setCartasMonje(Set<Monje> cartasMonje){
		this.monkCards=new TreeSet<Monje>(cartasMonje);
	}
	
	public void setScore(int score){
		this.score += score;
	}
	
	public void setSilenceVote() {
		this.votoSilencio = true;
	}
	
	public void setLibraryVisited() {
		libraryVisited = true;
	}
	//SETTERS
	
	
	/**
	 * returns true if the player has moved, else it returns false
	 * <p> 
	 * @return    boolean
	 */
	public boolean hasMoved(){
		return hasMoved;
	}
	
	public boolean votoSilencio(){
		return votoSilencio;
	}
	
	/**
	 * set the hasMoved boolean to false
	 * <p> 
	 * @return    void
	 */
	public void reset(){
		hasMoved=false;
		maxMoves = Constants.MAX_MOVES;
		votoSilencio=false;
	}
	
	
	//ANSWER QUESTIONS
	/**
	 * 
	 * @param hand
	 * @param features
	 * @return
	 */
	public int answer(int hand,List<Features> features){  // 1 o dos caracteristicas en cartas monje // true si va a la mano false si va ala hoja de sospechosos
		int cont = 0;
		if(hand==1){
			for(Monje monje:monkCards){
				if(monje.is(features))cont++;
			}
		}
		else if(hand==2){
			for(Suspect sospechoso:hojaSospechosos){
				if(sospechoso.getMonje().is(features)&& sospechoso.isMarcado()) cont++;
			}
		}
		return cont;
	}
	
	
	public boolean answer(int hand,String nombre){
		boolean check=false;
		if(hand==1){
			Iterator<Monje> itr =  monkCards.iterator();
			while(itr.hasNext() && !check){
				if(itr.next().getName().equals(nombre))check = true;
			}
		}
		else if(hand==2){
			Iterator<Suspect> itr = hojaSospechosos.iterator();
			while(itr.hasNext() && !check){
				Suspect sospechoso = itr.next();
				if(sospechoso.getMonje().getName().equals(nombre) && sospechoso.isMarcado()) check=true;
			}
		}
		return check;
	}
	
	
	public Monje getOneMonkWithFeature(Features feature) {
		
		Monje monk = null;
		List<Monje> monks = new ArrayList<Monje>();
		for(Monje m : monkCards) {
			if(m.is(feature)) monks.add(m);
		}
		if(monks.size()>0) {
			Random rnd = new Random();
			monk = monks.get(rnd.nextInt(monks.size()));
		}
		return monk;
	}
	//ANSWER QUESTIONS
	
	
	public void addCriptaCard(CryptaCard criptaCard) {
		criptaCardList.add(criptaCard);
	}
	
	public CryptaCard removeCriptaCard() {
		if(criptaCardList.size()>0) {
			return criptaCardList.remove(0);
		}
		else return null;
	}
	
	public void setNewCardToPlayersCardDeck(Monje card){
		 monkCards.add(card);
	}

	public  Monje getCardX(int position) throws NullPointerException{
		int cont = 0;
		Monje temp=null;
		for (Monje n : monkCards ){
			if (cont == position)	 temp= n;
			cont++;			 
		}
		monkCards.remove(temp);

		return temp;
	}
	
	
	public void marcarSospechosos(){
		for(Suspect s:hojaSospechosos){
			Monje m = s.getMonje();
			if(monkCards.contains(m)) s.setMarcado();
		}
		System.out.println(hojaSospechosos);
	}
	
	public void marcarSospechoso(String name){
		for(Suspect s:hojaSospechosos){
			Monje m = s.getMonje();
			if(m.getName().equalsIgnoreCase(name)) s.setMarcado();
		}
	}
	
	public void marcarSospechosos(List<Monje> monkListParam) {
		for(Monje m:monkListParam) {
			String monkName = m.getName();
			marcarSospechoso(monkName);
		}
	}


	@Override
	public String toString() {
		String casilla;
		if(ubication!=null) casilla = ubication.getSquareName();
		else casilla="no ubicado";
		return "nombre : " + playerName + ", color : " + color
				+ ", numero : " + playerNumber +", ubicacion : "+ casilla +"]";
	}

	

	@Override
	public int compareTo(Player o) {
		return (this.playerNumber-o.playerNumber);
	}

}
